TalkingData AdTracking Fraud Detection Challenge 是 TalkingData 在 Kaggle 上举办的一个数据挖掘比赛。最终取得的成绩是 Solo 银牌。
这个比赛历程比较有趣,应该可以说是我时间花费最少的比赛吧。最开始关注到这个比赛是 4 月 25 日,那时我便随便下载了个别人的结果提交,当时排名 300+,于是我就置之不理了。之后再开始做的时候已经是 5 月 2 日了,排名也掉到了 1100+。从 5 月 2 日至 5 月 7 日,我大概只用了 6 天(期间还有在忙其他的事情,因此也不是全脱产比赛),幸运的拿到一枚银牌。下图是我比赛期间的排名变化。
因为时间较短,我的结果都是来自于单模型 LightGBM,并没有尝试其他模型。因此我会分享比赛中我认为比较重要的两个部分:亿级数据的处理和特征构建。
项目源码:https://github.com/ShawnyXiao/2018-Kaggle-AdTrackingFraud
亿级数据的处理
该比赛提供的数据大约 10 G,有超过 1 亿个样本。如何利用有限的内存来处理这 10 G 的数据,对于这个比赛是十分关键的。比赛中,我大致使用过以下几个操作:
- 使用 Pandas 读取数据时,如果没有指定每列的数据类型,它会以最保守的方式来读取:使用
uint64
读取非负整型,使用float64
读取浮点数和带空值的整型。如果使用这种最保守的方式读取数据,带来的内存消耗是极大的。因此,使用适当的数据类型uint8
、uint16
、uint34
、float32
等来读取数据,能够很好的节约我们的内存资源。 - 很多变量我们在之后不会再使用了,但是如果一直被保存在内存中,也会耗费我们极为珍贵的内存资源。因此,当某个变量
a
(尤其占较大内存的变量)不再使用时,我们应该及时将它从内存中删除:del a
。 - 我们经常会使用某个变量引用不同的对象,这时会产生一些无法再继续引用的对象,理论上 Python 会自动帮我们做垃圾回收,但是需要触发某些条件。因此,我们可以经常性的调用函数:
gc.collect()
,来触发垃圾回收操作。 - 对于类别特征,我们一般会进行 One-hot 转换。如果不转换,模型会把类别特征当作有序的连续值来处理;如果转化了,特征维度会变得极大,内存耗费增大的同时模型的训练速度也会减慢。LightGBM 对于类别特征做了优化处理,只需要在准备数据时指定类别特征即可,这样不需要再对类别特征进行 One-hot 转换,因此不会增大内存耗费也不会减慢模型的训练速度。
特征构建
特征构建部分对于提分尤为关键。特征构建可以被分解成两个问题:基于什么数据集去构建特征和构建哪些特征。
1. 基于什么数据集去构建特征?
最开始的时候,对于比赛方提供 test_supplement
这个数据集的意图不是特别清楚,因此没有使用该数据。使用 train+test
这个数据集来构建特征,分数不高也不低,公榜 0.9800,在铜牌的位置;后来尝试使用了 train+test_supplement
这个数据集来构建特征,分数直接上升一个千,公榜 0.9813,在银牌的位置!因此,从这个现象我们可以察觉,从 train+test 提取的特征训练的模型的偏差(bias)是比 train+test_supplement
要大不少的。
2. 构建哪些特征?
- 基于
[ip, app, channel, device, os]
分组后,计算后一个的时间差 - 基于
[ip, os, device]
分组后,计算后一个的时间差 - 基于
[ip, os, device, app]
分组后,计算后一个的时间差 - 基于
[ip, channel]
分组后,计算前一个的时间差 - 基于
[ip, os]
分组后,计算前一个的时间差 - 基于
[ip]
分组后,统计channel
的 unique 数量 - 基于
[ip, device, os]
分组后,统计app
的 unique 数量 - 基于
[ip, day]
分组后,统计hour
的 unique 数量 - 基于
[ip]
分组后,统计app
的 unique 数量 - 基于
[ip, app]
分组后,统计os
的 unique 数量 - 基于
[ip]
分组后,统计device
的 unique 数量 - 基于
[app]
分组后,统计channel
的 unique 数量 - 基于
[ip]
分组后,统计os
的 cumcount 计数 - 基于
[ip, device, os]
分组后,统计app
的 cumcount 计数 - 基于
[ip, day, hour]
分组后,统计数量 - 基于
[ip, app]
分组后,统计数量 - 基于
[ip, app, os]
分组后,统计数量 - 基于
[ip, app, os]
分组后,统计day
的方差 - 基于不同分组的转化率特征(这个最后没时间做了,据说可以提升 5 个万分点)
嘿!
如果您有任何的想法,例如:发现某处有 bug、觉得我对某个方法的讲解不正确或者不透彻、有更加有创意的见解,欢迎随时发 issue 或者 pull request 或者直接与我讨论!另外您若能 star 或者 fork 这个项目以激励刚刚踏入数据挖掘的我,我会感激不尽~